package org.bees.cms.core;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;

import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.Transient;

import org.bees.cms.common.ThreadLocals;

/**
 * DataBase Access Object<br/>
 * 这个类主要是为了让Domain类封装仓储功能,实际上就是为了实现Domain跟Dao整合在一起提高Core层的可移植性
 * 
 * 默认所有实体类都是这个类的子类
 * 
 * @author 杨昌沛
 * 
 */
public abstract class Dao implements Persistable {

	private static EntityManager manager() {
		return ThreadLocals.ENTITY_MANAGERS.get();
	}

	public void persist() throws Exception {
		convert();
		manager().persist(this);
	}

	public void merge() throws Exception {
		convert();
		manager().merge(this);
	}

	public void delete() throws Exception {
		manager().remove(this);
	}

	public boolean exists() throws Exception {
		return this.getId() != null && manager().find(this.getClass(), this.getId()) != null;
	}

	public void refresh() throws Exception {
		manager().refresh(this);
	}

	private void convert() throws Exception {
		BeanInfo info = Introspector.getBeanInfo(this.getClass());
		PropertyDescriptor[] descriptors = info.getPropertyDescriptors();
		for (PropertyDescriptor descriptor : descriptors) {
			Method reader = descriptor.getReadMethod();
			Class<?> clazz = reader.getReturnType();
			if (clazz.isAnnotationPresent(Entity.class) && !reader.isAnnotationPresent(Transient.class)) {
				Persistable persistable = (Persistable) reader.invoke(this);
				Method writer = descriptor.getWriteMethod();
				if (persistable != null && persistable.getId() != null) {
					Object object = manager().getReference(clazz, persistable.getId());
					writer.invoke(this, object);
				} else {
					Object object = null;
					writer.invoke(this, object);
				}
			}
		}
	}

}
